﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Text;
using CodeProject.Data.Entity;
using InvoiceSample;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestProjectCS.Attributes;
using System.Data;

namespace TestProjectCS
{
	[TestClass]
	public class FolderRecursionTests : BaseInvoiceTests
	{
		[TestMethod]
		[RollingBackTransaction]
		public void AttachFolderWithChildrenTest()
		{
			CatalogFolder folder;

			using (var context = new SampleInvoiceContext())
			{
				var q = from f in context.CatalogFolderSet
						.Include("Children")
						where f.Parent == null
						select f;
				folder = q.First();
				ShowFolderWithChildren(folder, 0, 99);
				folder = context.DetachObjectGraph(folder);
			}

			ShowFolderWithChildren(folder, 0, 99);

			using (var context = new SampleInvoiceContext())
			{
				folder = context.AttachObjectGraph(folder, p => p.Children);

				ShowFolderWithChildren(folder, 0, 99);

				this.AssertContextChanges(context, 0, 0, 0);
			}
		}

		[TestMethod]
		[RollingBackTransaction]
		public void AttachFolderWithCircularReferencesTest()
		{
			CatalogFolder folder;

			using (var context = new SampleInvoiceContext())
			{
				var q = from f in context.CatalogFolderSet
						.Include("Children.Children.Children")
						where f.ID == 12
						select f;
				folder = q.First();
				ShowFolderWithChildren(folder, 0, 4);
				folder = context.DetachObjectGraph(folder);
			}

			ShowFolderWithChildren(folder, 0, 4);

			using (var context = new SampleInvoiceContext())
			{
				folder = context.AttachObjectGraph(folder, p => p.Children.First().Children);

				ShowFolderWithChildren(folder, 0, 4);

				this.AssertContextChanges(context, 0, 0, 0);
			}
		}

		[TestMethod]
		[RollingBackTransaction]
		public void QueryProductCatalogFolderReferenceOnlyTest()
		{
			using (var context = new SampleInvoiceContext())
			{
				var query = from prod in context.ProductSet
							.Include(p => p.Folder.ReferenceOnly())
							where prod.ID == 2
							select prod;

				// Assert reference is not loaded but entitykey is:
				foreach (Product prod in query)
				{
					Assert.IsFalse(prod.FolderReference.IsLoaded);
					Assert.AreEqual((long)9, prod.FolderReference.EntityKey.EntityKeyValues[0].Value);
				}
			}
		}

		[TestMethod]
		[RollingBackTransaction]
		public void SetProductCatalogFolderReferenceOnlyTest()
		{
			Product product;

			// Retrieve a detached product:
			using (var context = new SampleInvoiceContext())
			{
				product = context.ProductSet.Where(p => p.ID == 4).First();
				product = context.DetachObjectGraph(product);
			}

			// Change it's folder by setting the reference to a new EntityKey:
			product.FolderReference.EntityKey = new EntityKey("SampleInvoiceContext.CatalogFolderSet", "ID", (long)2);

			// Reattach the product and save changes:
			using (var context = new SampleInvoiceContext())
			{
				product = context.AttachObjectGraph(
					product,
					p => p.Folder.ReferenceOnly()
				);

				this.AssertContextChanges(context, 1, 0, 1);

				context.SaveChanges();
			}

			// Assert change was persisted:
			using (var context = new SampleInvoiceContext())
			{
				product = context.ProductSet
					.Include(p => p.Folder)
					.Where(p => p.ID == 3).First();
				Assert.AreEqual(11, product.Folder.ID);
			}
		}

		#region Helper Methods

		private void ShowFolderWithChildren(CatalogFolder folder, int depth, int maxDepth)
		{
			String margin = new String(' ', depth * 4);

			if (depth > maxDepth)
			{
				Console.WriteLine("{0}+ >> MaxDepth reached", margin);
			}
			else
			{
				Console.WriteLine("{0}+ {1:0000} - {2} ({3})", margin, folder.ID, folder.Name, folder.EntityState);
				
				depth++;
				margin = new String(' ', depth * 4);

				if (folder.Children.IsLoaded)
				{
					foreach (CatalogFolder subfolder in folder.Children)
					{
						ShowFolderWithChildren(subfolder, depth, maxDepth);
					}
				}
			}
		}

		#endregion
	}
}
